import React, {useContext, useEffect, useRef} from 'react';
import {PreloadedQuery, usePreloadedQuery} from 'react-relay/hooks';
import * as AuthCompQuery from "./__generated__/AuthCompQuery.graphql";
import UserContext from "./context/UserContext";
import RoutingContext from "./routing/RoutingContext";
//js 演示版import graphql from 'babel-plugin-relay/macro';可以的;
//ts版本只能这样;
const graphql = require("babel-plugin-relay/macro");

const { Suspense } = React;

//注意底下issueDetailQuery名字 要和上一级组件或路由器内的定义保证一样的。
//都要改的 PreloadedQuery<IssueDetailRootQuery.IssueDetailRootQuery> 类型也要改，import也该改。
interface Props {
    prepared: {
        rootQuery: PreloadedQuery<AuthCompQuery.AuthCompQuery>;
    }
    children: React.ReactNode;
}

/**
 * 为了实现逻辑：浏览器直接输入URI但是已经有了token登录过了，就不要再次跳转login页面；允许没授权访问/free/页面。
 * 不得已，必须用GlobalState提供user提前验证，光光依靠AuthComp无法搞定逻辑！
 * GlobalState只会在SPA启动执行一趟的。假如token失效继续SPA内部Link跳转无法知晓{后端会报错}，AuthComp是补充机制：
 * 本组件AuthComp在路由表置顶就算在SPA内部Link跳转也必执行一次的，幸亏：内部缓存不会太勤快发起服务端认证的，不会真的都发送网络请求的；
 * AuthComp是每个路由点击都会执行。假如token超时了，auth验证通不过。
 * 路由方式，SPA点击路由进入新页面的：虽然AuthComp在路由表置顶必过，但是不会触发发送服务端请求包的，有缓存机制。
 * AuthComp和GlobalState缺一不可了。???看看能够搞定
 * 变化策略：直接在浏览器输入地址访问必须经过登录页面，就算刚刚已经登录有token了。
 * SPA刚起启动render两边才有user
 * */
export default function AuthComp(props: Props) {
    //第一次啊运行吗？
    const mountedRef = useRef(false);
    const {history } = useContext(RoutingContext);
    const isPublic=isPublicAccsess(history.location.pathname);
    //const islogin=isLoginPage(history.location.pathname);
    // Defines *what* data the component needs via a query. The responsibility of
    // actually fetching this data belongs to the route definition: it calls
    // preloadQuery() with the query and variables, and the result is passed
    // on props.prepared.issuesQuery - see src/routes.ts
    //取数据比render（）还要早运行。数据准备好了，能避免折腾啊。一进来就已经有了数据，这跟apollo客户端不一样的。
    const data = usePreloadedQuery(
        graphql`
            query AuthCompQuery {
                auth
            }
        `,
        props.prepared.rootQuery,
    );
    //data没有取到数据的，会直接报错，不会继续执行下去的。usePreloadedQuery没数据页面代码就没意义哦。
    //刚加载render一边是没有user的，最快也要第二次render{地址栏进入模式、非SPA路由模式}。
    const {user, setUser} = useContext(UserContext);
    //必须放入在当中useEffect{ } ； 否则setUser非法的！
    //login页面不对：竟然return null 两次，还没有执行useEffect里面代码，useEffect里面代码段是看着像独立运行的，useEffect运行时其它代码段没有执行，useEffect只管自己代码，
    const {auth} = data;
    //必须 const 啊;  除非运行报错，否则后端非登录用户也会返回"{}"
    const authjs=JSON.parse(auth);    //当前看到的用户
    if(!authjs|| !authjs.id)
    {
        if(!isPublic)   window.location.href = "/login";
    }
    //console.log("AuthComp 目前render之后.mountedRef=", mountedRef.current,"user=",user);
    //这个useEffect的执行时间时机太奇怪了！！
    useEffect(() => {
        if(authjs && authjs.id && authjs.username) {
            if(!user)
                setUser(authjs);
            else {
                //简单判定
                if(JSON.stringify(user) !== JSON.stringify(authjs))
                    setUser(authjs);
            }
        }
    });

    //console.log("AuthComp see user=", user,"mountedRef.current=",mountedRef.current);
    if(!mountedRef.current) {
        mountedRef.current = true;
        //return null;重大毛病来源这里啊！！吃屎了！
    }
    else
    {
       if(!user && !isPublic)
             window.location.href = "/login";
    }

    /** 原来这里也有：显示内容；｛最开始置顶的菜单？｝;要么前面的，要么最后面的，难道中间、难道多个子组件;
     * 路由特点：每一级层次都要留下render();
     * 这个页面不需要显示内容；但是要会跳转登录页面；遇到没有授权用户的并且不是无需要授权的路由页面。
     * ??第一次进入页面，若是已经登录了，不就没必要跳转登录页面了吗？
     */
    return (
         <Suspense fallback={'Loading...'}>
             {props.children}
         </Suspense>
    );
}


//排除 不登录的人也允许访问
function  isPublicAccsess(path: string) {
    if(path === '/' || path.slice(0, 6) === '/free/' || path === '/login')
        return true;
    else
        return false;
}

